home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr25 / me310.zip / UE310C.ZIP / LINE.C < prev    next >
C/C++ Source or Header  |  1988-12-01  |  18KB  |  670 lines

  1. /*
  2.  * The functions in this file are a general set of line management utilities.
  3.  * They are the only routines that touch the text. They also touch the buffer
  4.  * and window structures, to make sure that the necessary updating gets done.
  5.  * There are routines in this file that handle the kill buffer too. It isn't
  6.  * here for any good reason.
  7.  *
  8.  * Note that this code only updates the dot and mark values in the window list.
  9.  * Since all the code acts on the current window, the buffer that we are
  10.  * editing must be being displayed, which means that "b_nwnd" is non zero,
  11.  * which means that the dot and mark values in the buffer headers are nonsense.
  12.  */
  13.  
  14. #include    <stdio.h>
  15. #include    "estruct.h"
  16. #include    "etype.h"
  17. #include    "edef.h"
  18. #include    "elang.h"
  19.  
  20. #define    BSIZE(a)    (a + NBLOCK - 1) & (~(NBLOCK - 1))
  21.  
  22. /*
  23.  * This routine allocates a block of memory large enough to hold a LINE
  24.  * containing "used" characters. Return a pointer to the new block, or
  25.  * NULL if there isn't any memory left. Print a message in the message
  26.  * line if no space.
  27.  */
  28.  
  29. LINE *PASCAL NEAR lalloc(used)
  30.  
  31. register int used;
  32.  
  33. {
  34.     register LINE    *lp;
  35.  
  36.     if ((lp = (LINE *)malloc(sizeof(LINE)+used)) == NULL) {
  37.         mlwrite(TEXT99);
  38. /*                      "[OUT OF MEMORY]" */
  39.         return(NULL);
  40.     }
  41.     lp->l_size = used;
  42.     lp->l_used = used;
  43.     return(lp);
  44. }
  45.  
  46. /*
  47.  * Delete line "lp". Fix all of the links that might point at it (they are
  48.  * moved to offset 0 of the next line. Unlink the line from whatever buffer it
  49.  * might be in. Release the memory. The buffers are updated too; the magic
  50.  * conditions described in the above comments don't hold here.
  51.  */
  52. PASCAL NEAR lfree(lp)
  53. register LINE    *lp;
  54. {
  55.     register BUFFER *bp;
  56.     register WINDOW *wp;
  57.     register int cmark;        /* current mark */
  58.  
  59.     wp = wheadp;
  60.     while (wp != NULL) {
  61.         if (wp->w_linep == lp)
  62.             wp->w_linep = lp->l_fp;
  63.         if (wp->w_dotp    == lp) {
  64.             wp->w_dotp  = lp->l_fp;
  65.             wp->w_doto  = 0;
  66.         }
  67.         for (cmark = 0; cmark < NMARKS; cmark++) {
  68.             if (wp->w_markp[cmark] == lp) {
  69.                 wp->w_markp[cmark] = lp->l_fp;
  70.                 wp->w_marko[cmark] = 0;
  71.             }
  72.         }
  73.         wp = wp->w_wndp;
  74.     }
  75.     bp = bheadp;
  76.     while (bp != NULL) {
  77.         if (bp->b_nwnd == 0) {
  78.             if (bp->b_dotp    == lp) {
  79.                 bp->b_dotp = lp->l_fp;
  80.                 bp->b_doto = 0;
  81.             }
  82.             for (cmark = 0; cmark < NMARKS; cmark++) {
  83.                 if (bp->b_markp[cmark] == lp) {
  84.                     bp->b_markp[cmark] = lp->l_fp;
  85.                     bp->b_marko[cmark] = 0;
  86.                 }
  87.             }
  88.         }
  89.         bp = bp->b_bufp;
  90.     }
  91.     lp->l_bp->l_fp = lp->l_fp;
  92.     lp->l_fp->l_bp = lp->l_bp;
  93.     free((char *) lp);
  94. }
  95.  
  96. /*
  97.  * This routine gets called when a character is changed in place in the current
  98.  * buffer. It updates all of the required flags in the buffer and window
  99.  * system. The flag used is passed as an argument; if the buffer is being
  100.  * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
  101.  * mode line needs to be updated (the "*" has to be set).
  102.  */
  103. PASCAL NEAR lchange(flag)
  104. register int    flag;
  105. {
  106.     register WINDOW *wp;
  107.  
  108.     if (curbp->b_nwnd != 1)         /* Ensure hard.     */
  109.         flag = WFHARD;
  110.     if ((curbp->b_flag&BFCHG) == 0) {    /* First change, so    */
  111.         flag |= WFMODE;         /* update mode lines.    */
  112.         curbp->b_flag |= BFCHG;
  113.     }
  114.  
  115.     /* make sure all the needed windows get this flag */
  116.     wp = wheadp;
  117.     while (wp != NULL) {
  118.         if (wp->w_bufp == curbp)
  119.             wp->w_flag |= flag;
  120.         wp = wp->w_wndp;
  121.     }
  122. }
  123.  
  124. PASCAL NEAR insspace(f, n)    /* insert spaces forward into text */
  125.  
  126. int f, n;    /* default flag and numeric argument */
  127.  
  128. {
  129.     linsert(n, ' ');
  130.     backchar(f, n);
  131. }
  132.  
  133. /*
  134.  * linstr -- Insert a string at the current point
  135.  */
  136.  
  137. PASCAL NEAR linstr(instr)
  138. char    *instr;
  139. {
  140.     register int status = TRUE;
  141.  
  142.     if (instr != NULL)
  143.         while (*instr && status == TRUE) {
  144.             status = ((*instr == '\r') ? lnewline(): linsert(1, *instr));
  145.  
  146.             /* Insertion error? */
  147.             if (status != TRUE) {
  148.                 mlwrite(TEXT168);
  149. /*                                      "%%Can not insert string" */
  150.                 break;
  151.             }
  152.             instr++;
  153.         }
  154.     return(status);
  155. }
  156.  
  157. /*
  158.  * Insert "n" copies of the character "c" at the current location of dot. In
  159.  * the easy case all that happens is the text is stored in the line. In the
  160.  * hard case, the line has to be reallocated. When the window list is updated,
  161.  * take special care; I screwed it up once. You always update dot in the
  162.  * current window. You update mark, and a dot in another window, if it is
  163.  * greater than the place where you did the insert. Return TRUE if all is
  164.  * well, and FALSE on errors.
  165.  */
  166.  
  167. PASCAL NEAR linsert(n, c)
  168. int    n;
  169. char    c;
  170. {
  171.     register char    *cp1;
  172.     register char    *cp2;
  173.     register LINE    *lp1;
  174.     register LINE    *lp2;
  175.     register LINE    *lp3;
  176.     register int    doto;
  177.     register int    i;
  178.     register WINDOW *wp;
  179.     int cmark;        /* current mark */
  180.  
  181.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  182.         return(rdonly());    /* we are in read only mode    */
  183.     lchange(WFEDIT);
  184.     lp1 = curwp->w_dotp;            /* Current line     */
  185.     if (lp1 == curbp->b_linep) {        /* At the end: special    */
  186.         if (curwp->w_doto != 0) {
  187.             mlwrite(TEXT170);
  188. /*                              "bug: linsert" */
  189.             return(FALSE);
  190.         }
  191.         if ((lp2=lalloc(BSIZE(n))) == NULL)    /* Allocate new line    */
  192.             return(FALSE);
  193.         lp2->l_used = n;
  194.         lp3 = lp1->l_bp;        /* Previous line    */
  195.         lp3->l_fp = lp2;        /* Link in        */
  196.         lp2->l_fp = lp1;
  197.         lp1->l_bp = lp2;
  198.         lp2->l_bp = lp3;
  199.         for (i=0; i<n; ++i)
  200.             lp2->l_text[i] = c;
  201.         curwp->w_dotp = lp2;
  202.         curwp->w_doto = n;
  203.         return(TRUE);
  204.     }
  205.     doto = curwp->w_doto;            /* Save for later.    */
  206.     if (lp1->l_used+n > lp1->l_size) {    /* Hard: reallocate    */
  207.         if ((lp2=lalloc(BSIZE(lp1->l_used+n))) == NULL)
  208.             return(FALSE);
  209.         lp2->l_used = lp1->l_used+n;
  210.         cp1 = &lp1->l_text[0];
  211.         cp2 = &lp2->l_text[0];
  212.         while (cp1 != &lp1->l_text[doto])
  213.             *cp2++ = *cp1++;
  214.         cp2 += n;
  215.         while (cp1 != &lp1->l_text[lp1->l_used])
  216.             *cp2++ = *cp1++;
  217.         lp1->l_bp->l_fp = lp2;
  218.         lp2->l_fp = lp1->l_fp;
  219.         lp1->l_fp->l_bp = lp2;
  220.         lp2->l_bp = lp1->l_bp;
  221.         free((char *) lp1);
  222.     } else {                /* Easy: in place    */
  223.         lp2 = lp1;            /* Pretend new line    */
  224.         lp2->l_used += n;
  225.         cp2 = &lp1->l_text[lp1->l_used];
  226.         cp1 = cp2-n;
  227.         while (cp1 != &lp1->l_text[doto])
  228.             *--cp2 = *--cp1;
  229.     }
  230.     for (i=0; i<n; ++i)            /* Add the characters    */
  231.         lp2->l_text[doto+i] = c;
  232.     wp = wheadp;                /* Update windows    */
  233.     while (wp != NULL) {
  234.         if (wp->w_linep == lp1)
  235.             wp->w_linep = lp2;
  236.         if (wp->w_dotp == lp1) {
  237.             wp->w_dotp = lp2;
  238.             if (wp==curwp || wp->w_doto>doto)
  239.                 wp->w_doto += n;
  240.         }
  241.         for (cmark = 0; cmark < NMARKS; cmark++) {
  242.             if (wp->w_markp[cmark] == lp1) {
  243.                 wp->w_markp[cmark] = lp2;
  244.                 if (wp->w_marko[cmark] > doto)
  245.                     wp->w_marko[cmark] += n;
  246.             }
  247.         }
  248.         wp = wp->w_wndp;
  249.     }
  250.     return(TRUE);
  251. }
  252.  
  253. /*
  254.  * Overwrite a character into the current line at the current position
  255.  *
  256.  */
  257.  
  258. PASCAL NEAR lowrite(c)
  259.  
  260. char c;        /* character to overwrite on current position */
  261.  
  262. {
  263.     if (curwp->w_doto < curwp->w_dotp->l_used &&
  264.         (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
  265.          (curwp->w_doto) % 8 == 7))
  266.             ldelete(1L, FALSE);
  267.     return(linsert(1, c));
  268. }
  269.  
  270. /*
  271.  * lover -- Overwrite a string at the current point
  272.  */
  273.  
  274. PASCAL NEAR lover(ostr)
  275.  
  276. char    *ostr;
  277.  
  278. {
  279.     register int status = TRUE;
  280.  
  281.     if (ostr != NULL)
  282.         while (*ostr && status == TRUE) {
  283.             status = ((*ostr == '\r') ? lnewline(): lowrite(*ostr));
  284.  
  285.             /* Insertion error? */
  286.             if (status != TRUE) {
  287.                 mlwrite(TEXT172);
  288. /*                                      "%%Out of memory while overwriting" */
  289.                 break;
  290.             }
  291.             ostr++;
  292.         }
  293.     return(status);
  294. }
  295.  
  296. /*
  297.  * Insert a newline into the buffer at the current location of dot in the
  298.  * current window. The funny ass-backwards way it does things is not a botch;
  299.  * it just makes the last line in the file not a special case. Return TRUE if
  300.  * everything works out and FALSE on error (memory allocation failure). The
  301.  * update of dot and mark is a bit easier then in the above case, because the
  302.  * split forces more updating.
  303.  */
  304. PASCAL NEAR lnewline()
  305. {
  306.     register char    *cp1;
  307.     register char    *cp2;
  308.     register LINE    *lp1;
  309.     register LINE    *lp2;
  310.     register int    doto;
  311.     register WINDOW *wp;
  312.     int cmark;        /* current mark */
  313.  
  314.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  315.         return(rdonly());    /* we are in read only mode    */
  316.     lchange(WFHARD);
  317.     lp1  = curwp->w_dotp;            /* Get the address and    */
  318.     doto = curwp->w_doto;            /* offset of "."    */
  319.     if ((lp2=lalloc(doto)) == NULL)     /* New first half line    */
  320.         return(FALSE);
  321.     cp1 = &lp1->l_text[0];            /* Shuffle text around    */
  322.     cp2 = &lp2->l_text[0];
  323.     while (cp1 != &lp1->l_text[doto])
  324.         *cp2++ = *cp1++;
  325.     cp2 = &lp1->l_text[0];
  326.     while (cp1 != &lp1->l_text[lp1->l_used])
  327.         *cp2++ = *cp1++;
  328.     lp1->l_used -= doto;
  329.     lp2->l_bp = lp1->l_bp;
  330.     lp1->l_bp = lp2;
  331.     lp2->l_bp->l_fp = lp2;
  332.     lp2->l_fp = lp1;
  333.     wp = wheadp;                /* Windows        */
  334.     while (wp != NULL) {
  335.         if (wp->w_linep == lp1)
  336.             wp->w_linep = lp2;
  337.         if (wp->w_dotp == lp1) {
  338.             if (wp->w_doto < doto)
  339.                 wp->w_dotp = lp2;
  340.             else
  341.                 wp->w_doto -= doto;
  342.         }
  343.         for (cmark = 0; cmark < NMARKS; cmark++) {
  344.             if (wp->w_markp[cmark] == lp1) {
  345.                 if (wp->w_marko[cmark] < doto)
  346.                     wp->w_markp[cmark] = lp2;
  347.                 else
  348.                     wp->w_marko[cmark] -= doto;
  349.             }
  350.         }
  351.         wp = wp->w_wndp;
  352.     }
  353.     return(TRUE);
  354. }
  355.  
  356. /*
  357.  * This function deletes "n" bytes, starting at dot. It understands how to deal
  358.  * with end of lines, etc. It returns TRUE if all of the characters were
  359.  * deleted, and FALSE if they were not (because dot ran into the end of the
  360.  * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
  361.  */
  362. PASCAL NEAR ldelete(n, kflag)
  363.  
  364. long n;     /* # of chars to delete */
  365. int kflag;    /* put killed text in kill buffer flag */
  366.  
  367. {
  368.     register char    *cp1;
  369.     register char    *cp2;
  370.     register LINE    *dotp;
  371.     register int    doto;
  372.     register int    chunk;
  373.     register WINDOW *wp;
  374.     int cmark;        /* current mark */
  375.  
  376.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  377.         return(rdonly());    /* we are in read only mode    */
  378.     while (n != 0) {
  379.         dotp = curwp->w_dotp;
  380.         doto = curwp->w_doto;
  381.         if (dotp == curbp->b_linep)    /* Hit end of buffer.    */
  382.             return(FALSE);
  383.         chunk = dotp->l_used-doto;    /* Size of chunk.    */
  384.         if (chunk > n)
  385.             chunk = n;
  386.         if (chunk == 0) {        /* End of line, merge.    */
  387.             lchange(WFHARD);
  388.             if (ldelnewline() == FALSE
  389.             || (kflag!=FALSE && kinsert('\r')==FALSE))
  390.                 return(FALSE);
  391.             --n;
  392.             continue;
  393.         }
  394.         lchange(WFEDIT);
  395.         cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  396.         cp2 = cp1 + chunk;
  397.         if (kflag != FALSE) {        /* Kill?        */
  398.             while (cp1 != cp2) {
  399.                 if (kinsert(*cp1) == FALSE)
  400.                     return(FALSE);
  401.                 ++cp1;
  402.             }
  403.             cp1 = &dotp->l_text[doto];
  404.         }
  405.         while (cp2 != &dotp->l_text[dotp->l_used])
  406.             *cp1++ = *cp2++;
  407.         dotp->l_used -= chunk;
  408.         wp = wheadp;            /* Fix windows        */
  409.         while (wp != NULL) {
  410.             if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  411.                 wp->w_doto -= chunk;
  412.                 if (wp->w_doto < doto)
  413.                     wp->w_doto = doto;
  414.             }
  415.             for (cmark = 0; cmark < NMARKS; cmark++) {
  416.                 if (wp->w_markp[cmark]==dotp && wp->w_marko[cmark]>=doto) {
  417.                     wp->w_marko[cmark] -= chunk;
  418.                     if (wp->w_marko[cmark] < doto)
  419.                         wp->w_marko[cmark] = doto;
  420.                 }
  421.             }
  422.             wp = wp->w_wndp;
  423.         }
  424.         n -= chunk;
  425.     }
  426.     return(TRUE);
  427. }
  428.  
  429. /* getctext:    grab and return a string with the text of
  430.         the current line
  431. */
  432.  
  433. char *PASCAL NEAR getctext()
  434.  
  435. {
  436.     register LINE *lp;    /* line to copy */
  437.     register int size;    /* length of line to return */
  438.     register char *sp;    /* string pointer into line */
  439.     register char *dp;    /* string pointer into returned line */
  440.     char rline[NSTRING];    /* line to return */
  441.  
  442.     /* find the contents of the current line and its length */
  443.     lp = curwp->w_dotp;
  444.     sp = lp->l_text;
  445.     size = lp->l_used;
  446.     if (size >= NSTRING)
  447.         size = NSTRING - 1;
  448.  
  449.     /* copy it across */
  450.     dp = rline;
  451.     while (size--)
  452.         *dp++ = *sp++;
  453.     *dp = 0;
  454.     return(rline);
  455. }
  456.  
  457. /* putctext:    replace the current line with the passed in text    */
  458.  
  459. PASCAL NEAR putctext(iline)
  460.  
  461. char *iline;    /* contents of new line */
  462.  
  463. {
  464.     register int status;
  465.  
  466.     /* delete the current line */
  467.     curwp->w_doto = 0;    /* starting at the beginning of the line */
  468.     if ((status = killtext(TRUE, 1)) != TRUE)
  469.         return(status);
  470.  
  471.     /* insert the new line */
  472.     if ((status = linstr(iline)) != TRUE)
  473.         return(status);
  474.     status = lnewline();
  475.     backline(TRUE, 1);
  476.     return(status);
  477. }
  478.  
  479. /*
  480.  * Delete a newline. Join the current line with the next line. If the next line
  481.  * is the magic header line always return TRUE; merging the last line with the
  482.  * header line can be thought of as always being a successful operation, even
  483.  * if nothing is done, and this makes the kill buffer work "right". Easy cases
  484.  * can be done by shuffling data around. Hard cases require that lines be moved
  485.  * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
  486.  * "ldelete" only.
  487.  */
  488. PASCAL NEAR ldelnewline()
  489. {
  490.     register char    *cp1;
  491.     register char    *cp2;
  492.     register LINE    *lp1;
  493.     register LINE    *lp2;
  494.     register LINE    *lp3;
  495.     register WINDOW *wp;
  496.     int cmark;        /* current mark */
  497.  
  498.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  499.         return(rdonly());    /* we are in read only mode    */
  500.     lp1 = curwp->w_dotp;
  501.     lp2 = lp1->l_fp;
  502.     if (lp2 == curbp->b_linep) {        /* At the buffer end.    */
  503.         if (lp1->l_used == 0)        /* Blank line.        */
  504.             lfree(lp1);
  505.         return(TRUE);
  506.     }
  507.     if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  508.         cp1 = &lp1->l_text[lp1->l_used];
  509.         cp2 = &lp2->l_text[0];
  510.         while (cp2 != &lp2->l_text[lp2->l_used])
  511.             *cp1++ = *cp2++;
  512.         wp = wheadp;
  513.         while (wp != NULL) {
  514.             if (wp->w_linep == lp2)
  515.                 wp->w_linep = lp1;
  516.             if (wp->w_dotp == lp2) {
  517.                 wp->w_dotp  = lp1;
  518.                 wp->w_doto += lp1->l_used;
  519.             }
  520.             for (cmark = 0; cmark < NMARKS; cmark++) {
  521.                 if (wp->w_markp[cmark] == lp2) {
  522.                     wp->w_markp[cmark]  = lp1;
  523.                     wp->w_marko[cmark] += lp1->l_used;
  524.                 }
  525.             }
  526.             wp = wp->w_wndp;
  527.         }
  528.         lp1->l_used += lp2->l_used;
  529.         lp1->l_fp = lp2->l_fp;
  530.         lp2->l_fp->l_bp = lp1;
  531.         free((char *) lp2);
  532.         return(TRUE);
  533.     }
  534.     if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
  535.         return(FALSE);
  536.     cp1 = &lp1->l_text[0];
  537.     cp2 = &lp3->l_text[0];
  538.     while (cp1 != &lp1->l_text[lp1->l_used])
  539.         *cp2++ = *cp1++;
  540.     cp1 = &lp2->l_text[0];
  541.     while (cp1 != &lp2->l_text[lp2->l_used])
  542.         *cp2++ = *cp1++;
  543.     lp1->l_bp->l_fp = lp3;
  544.     lp3->l_fp = lp2->l_fp;
  545.     lp2->l_fp->l_bp = lp3;
  546.     lp3->l_bp = lp1->l_bp;
  547.     wp = wheadp;
  548.     while (wp != NULL) {
  549.         if (wp->w_linep==lp1 || wp->w_linep==lp2)
  550.             wp->w_linep = lp3;
  551.         if (wp->w_dotp == lp1)
  552.             wp->w_dotp  = lp3;
  553.         else if (wp->w_dotp == lp2) {
  554.             wp->w_dotp  = lp3;
  555.             wp->w_doto += lp1->l_used;
  556.         }
  557.         for (cmark = 0; cmark < NMARKS; cmark++) {
  558.             if (wp->w_markp[cmark] == lp1)
  559.                 wp->w_markp[cmark]  = lp3;
  560.             else if (wp->w_markp[cmark] == lp2) {
  561.                 wp->w_markp[cmark]  = lp3;
  562.                 wp->w_marko[cmark] += lp1->l_used;
  563.             }
  564.         }
  565.         wp = wp->w_wndp;
  566.     }
  567.     free((char *) lp1);
  568.     free((char *) lp2);
  569.     return(TRUE);
  570. }
  571.  
  572. /*
  573.  * Delete all of the text saved in the kill buffer. Called by commands when a
  574.  * new kill context is being created. The kill buffer array is released, just
  575.  * in case the buffer has grown to immense size. No errors.
  576.  */
  577. PASCAL NEAR kdelete()
  578. {
  579.     KILL *kp;    /* ptr to scan kill buffer chunk list */
  580.  
  581.     if (kbufh != NULL) {
  582.  
  583.         /* first, delete all the chunks */
  584.         kbufp = kbufh;
  585.         while (kbufp != NULL) {
  586.             kp = kbufp->d_next;
  587.             free(kbufp);
  588.             kbufp = kp;
  589.         }
  590.  
  591.         /* and reset all the kill buffer pointers */
  592.         kbufh = kbufp = NULL;
  593.         kused = KBLOCK;             
  594.     }
  595. }
  596.  
  597. /*
  598.  * Insert a character to the kill buffer, allocating new chunks as needed.
  599.  * Return TRUE if all is well, and FALSE on errors.
  600.  */
  601.  
  602. PASCAL NEAR kinsert(c)
  603.  
  604. char c;        /* character to insert in the kill buffer */
  605.  
  606. {
  607.     KILL *nchunk;    /* ptr to newly malloced chunk */
  608.  
  609.     /* check to see if we need a new chunk */
  610.     if (kused >= KBLOCK) {
  611.         if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL)
  612.             return(FALSE);
  613.         if (kbufh == NULL)    /* set head ptr if first time */
  614.             kbufh = nchunk;
  615.         if (kbufp != NULL)    /* point the current to this new one */
  616.             kbufp->d_next = nchunk;
  617.         kbufp = nchunk;
  618.         kbufp->d_next = NULL;
  619.         kused = 0;
  620.     }
  621.  
  622.     /* and now insert the character */
  623.     kbufp->d_chunk[kused++] = c;
  624.     return(TRUE);
  625. }
  626.  
  627. /*
  628.  * Yank text back from the kill buffer. This is really easy. All of the work
  629.  * is done by the standard insert routines. All you do is run the loop, and
  630.  * check for errors. Bound to "C-Y".
  631.  */
  632. PASCAL NEAR yank(f, n)
  633. {
  634.     register int    c;
  635.     register int    i;
  636.     register char    *sp;    /* pointer into string to insert */
  637.     KILL *kp;        /* pointer into kill buffer */
  638.  
  639.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  640.         return(rdonly());    /* we are in read only mode    */
  641.     if (n < 0)
  642.         return(FALSE);
  643.     /* make sure there is something to yank */
  644.     if (kbufh == NULL)
  645.         return(TRUE);        /* not an error, just nothing */
  646.  
  647.     /* for each time.... */
  648.     while (n--) {
  649.         kp = kbufh;
  650.         while (kp != NULL) {
  651.             if (kp->d_next == NULL)
  652.                 i = kused;
  653.             else
  654.                 i = KBLOCK;
  655.             sp = kp->d_chunk;
  656.             while (i--) {
  657.                 if ((c = *sp++) == '\r') {
  658.                     if (lnewline() == FALSE)
  659.                         return(FALSE);
  660.                 } else {
  661.                     if (linsert(1, c) == FALSE)
  662.                         return(FALSE);
  663.                 }
  664.             }
  665.             kp = kp->d_next;
  666.         }
  667.     }
  668.     return(TRUE);
  669. }
  670.